module IPFS.Client.Command.Log (
  ls,
  tail,
  level,
  LogListInfo(..),
  LevelInfo(..),
  LogLevel(..)
) where

import Prelude

import Data.Argonaut (Json, decodeJson, fromString, jsonParser)
import Data.Argonaut.Decode (class DecodeJson, (.:))
import Data.Either (Either(..))
import Data.Generic.Rep (class Generic)
import Data.Generic.Rep.Show (genericShow)
import Data.Maybe (Maybe(..))
import Data.Tuple (Tuple)
import Data.Tuple.Nested ((/\))
import Effect (Effect)
import Effect.Aff (Aff)
import Foreign.Object as O
import IPFS.Client (Client)
import IPFS.Client.Command (Command, defCommand)
import IPFS.Client.Utils.SendRequest (execEffectStreamBuffer, execJsonCommand)
import Network.HTTP as HTTP
import Node.Buffer (Buffer)
import Node.Buffer as Buf
import Node.Encoding (Encoding(..))
import Node.SteamEx.Readable as SR
import Node.SteamEx.Readable as SW
import Node.Stream.Helper.Split2 as SP
import Node.StreamEx.Types (Readable, toReadable, toWritable)

------------------------------ls-----------------------------

newtype LogListInfo = LogListInfo (Array String)

derive instance genericLogListInfo :: Generic LogListInfo _
instance showLogListInfo :: Show LogListInfo where
  show s = genericShow s

instance logListInfoDecodeJson :: DecodeJson LogListInfo where
  decodeJson::Json -> Either String LogListInfo
  decodeJson json = do
    dJson <- decodeJson json
    arr    <- dJson .: "Strings"
    pure $ LogListInfo arr

listCommand::Command
listCommand = defCommand {path = "log/ls", args = Nothing ,qs = O.empty}

ls::Client -> Aff (Either String LogListInfo)
ls client = execJsonCommand client listCommand

------------------------------tail-----------------------------

tailCommand::Command
tailCommand = defCommand {path = "log/tail", args = Nothing ,qs = O.empty , isBuffer = false}

tail::Client -> (HTTP.Response -> Effect Unit) -> (Either String Json -> Effect Unit) -> Effect Unit
tail client startCallback callback  = do
  _ <- execEffectStreamBuffer client tailCommand startCallback buffer2jsonStream
  pure unit
 where
  buffer2jsonStream::Either String (Readable Buffer) -> Effect Unit
  buffer2jsonStream (Left  str) = callback $ Left str
  buffer2jsonStream (Right stream) = do
    splitStream <- SP.split2EX
    let readW = (toReadable stream::Readable Buffer)
    SW.pipe readW (toWritable splitStream) Nothing
    SR.onData (toReadable splitStream::Readable Buffer) (\buf -> do
                                                          str <- Buf.toString UTF8 buf
                                                          callback $ jsonParser str
                                                        )
    pure unit

------------------------------level-----------------------------
data LogLevel = Debug | Info | Warning | Error | Critical

derive instance genericLogLevel :: Generic LogLevel _
instance showLogLevel :: Show LogLevel where
  show s = genericShow s

newtype LevelInfo = LevelInfo String

derive instance genericLevelInfo :: Generic LevelInfo _
instance showLevelInfo :: Show LevelInfo where
  show s = genericShow s

instance levelInfoDecodeJson :: DecodeJson LevelInfo where
  decodeJson::Json -> Either String LevelInfo
  decodeJson json = do
    dJson <- decodeJson json
    msg    <- dJson .: "Message"
    pure $ LevelInfo msg


levelCommand::String -> LogLevel -> Command
levelCommand subsystem loglevel = defCommand {path = "log/level", 
                                              args = Just [fromString subsystem,fromString $ show loglevel] ,
                                              qs = O.empty}

level::Client -> String -> LogLevel -> Aff (Either String LevelInfo)
level client subsystem loglevel = execJsonCommand client $ levelCommand subsystem loglevel 